﻿namespace TestTool.Tests.Common.NotificationConsumer
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Net;
    using System.Runtime.InteropServices;
    using System.Text.RegularExpressions;

    public class HttpSoapServer : IDisposable
    {
        private Uri _address;
        private HttpListener _listener = new HttpListener();
        public Action<Exception> OnError;
        public Action<byte[]> OnMessage;

        public HttpSoapServer(string address)
        {
            this._address = new Uri(address);
            this._listener.Prefixes.Add(address);
        }

        public void Dispose()
        {
            this.Stop();
        }

        protected void GetContextCallback(IAsyncResult ar)
        {
            try
            {
                HttpListenerContext context = null;
                HttpListener asyncState = (HttpListener) ar.AsyncState;
                try
                {
                    string str;
                    context = asyncState.EndGetContext(ar);
                    HttpListenerRequest request = context.Request;
                    if (!this.ValidateRequest(request, out str))
                    {
                        this.OnError(new Exception(str));
                    }
                    else
                    {
                        MemoryStream stream = new MemoryStream();
                        byte[] buffer = new byte[0x200];
                        while (true)
                        {
                            int count = context.Request.InputStream.Read(buffer, 0, buffer.Length);
                            if (count == 0)
                            {
                                break;
                            }
                            stream.Write(buffer, 0, count);
                        }
                        this.OnMessageReceived(stream.ToArray());
                    }
                    HttpListenerResponse response = context.Response;
                    response.StatusCode = 200;
                    response.ContentLength64 = 0L;
                    response.Close();
                }
                catch (Exception exception)
                {
                    Trace.WriteLine(string.Format("{0} HttpSoapServer::GetContextCallback error [{1}]", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss:fff"), exception.Message));
                    Trace.Flush();
                }
                asyncState.BeginGetContext(new AsyncCallback(this.GetContextCallback), asyncState);
            }
            catch (Exception exception2)
            {
                Trace.WriteLine(string.Format("{0} HttpSoapServer::GetContextCallback2 error [{1}]", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss:fff"), exception2.Message));
                Trace.Flush();
            }
        }

        protected virtual void OnMessageReceived(byte[] data)
        {
            if (this.OnMessage != null)
            {
                this.OnMessage(data);
            }
        }

        public void Start()
        {
            this._listener.Start();
            this._listener.BeginGetContext(new AsyncCallback(this.GetContextCallback), this._listener);
        }

        public void Stop()
        {
            try
            {
                if (this._listener != null)
                {
                    this._listener.Stop();
                }
            }
            catch
            {
            }
        }

        protected bool ValidateContentType(HttpListenerRequest request)
        {
            string[] strArray = request.ContentType.Split(new char[] { ';' });
            if (strArray.Length == 0)
            {
                return false;
            }
            string x = strArray[0];
            if (StringComparer.InvariantCultureIgnoreCase.Compare(x, "application/soap+xml") != 0)
            {
                return false;
            }
            for (int i = 1; i < strArray.Length; i++)
            {
                string[] strArray2 = strArray[i].Trim().Split(new char[] { '=' });
                if (strArray2.Length > 1)
                {
                    if (StringComparer.InvariantCultureIgnoreCase.Compare(strArray2[0], "charset") == 0)
                    {
                        if (StringComparer.InvariantCultureIgnoreCase.Compare(strArray2[1], "utf-8") != 0)
                        {
                            return false;
                        }
                    }
                    else if (StringComparer.InvariantCultureIgnoreCase.Compare(strArray2[0], "action") != 0)
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        protected bool ValidateRequest(HttpListenerRequest request, out string reason)
        {
            reason = null;
            if (request.HttpMethod != "POST")
            {
                reason = string.Format("Unexpected HTTP method: {0}", request.HttpMethod);
            }
            else if (!this.ValidateContentType(request))
            {
                reason = string.Format("Unexpected content type: {0}", request.ContentType);
            }
            else if (!object.Equals(request.Url, this._address))
            {
                reason = string.Format("Unexpected request url: {0}", request.Url);
            }
            else
            {
                Regex regex = new Regex("^(/([A-Za-z0-9_])+)+/?$");
                if (!regex.IsMatch(request.RawUrl))
                {
                    reason = string.Format("Request-URI in POST line of HTTP request ('{0}') is incorrect", request.RawUrl);
                }
            }
            return (reason == null);
        }
    }
}

